#include "planner/logical_operators.h"

#include <memory>

#include "common/node_utils.h"
#include "planner/operator_visitor.h"

extern "C" {
#include <postgres.h>

#include <nodes/nodes.h>
#include <nodes/parsenodes.h>
#include <nodes/primnodes.h>
}

namespace optimizer {

std::shared_ptr<Operator> LogicalSetOperation::Copy() const {
  return std::make_shared<LogicalSetOperation>(type_, is_all_);
}

hash_t LogicalSetOperation::Hash() const {
  hash_t hash = Operator::Hash();
  hash = HashUtil::CombineHashes(hash, HashUtil::Hash(is_all_));
  return hash;
}

bool LogicalSetOperation::operator==(const Operator &r) const {
  if (!Operator::operator==(r))
    return false;

  const auto &node = CastTo<LogicalSetOperation>();
  return is_all_ == node.is_all_;
}

std::shared_ptr<Operator> LogicalJoin::Copy() const {
  return std::make_shared<LogicalJoin>(join_type_, copyObject(expressions_));
}

hash_t LogicalJoin::Hash() const {
  hash_t hash = Operator::Hash();
  hash = HashUtil::CombineHashes(hash, HashUtil::Hash(join_type_));
  return hash;
}

bool LogicalJoin::operator==(const Operator &r) const {
  if (!Operator::operator==(r))
    return false;

  const auto &node = CastTo<LogicalJoin>();
  return join_type_ == node.join_type_;
}

std::shared_ptr<Operator> LogicalAggregate::Copy() const {
  return std::make_shared<LogicalAggregate>(GetGroupExpressions(), GetAggExpressions());
}

hash_t LogicalAggregate::Hash() const {
  return HashUtil::CombineHashes(Operator::Hash(), HashUtil::Hash(static_cast<int>(agg_expr_state_)));
}

bool LogicalAggregate::operator==(const Operator &r) const {
  if (!Operator::operator==(r))
    return false;

  const auto &node = CastTo<LogicalAggregate>();
  return agg_expr_state_ == node.agg_expr_state_;
}

void LeafOperator::Accept(OperatorVisitor *v) {
  v->Visit(this);
}
void LogicalGet::Accept(OperatorVisitor *v) {
  v->Visit(this);
}

void LogicalLimit::Accept(OperatorVisitor *v) {
  v->Visit(this);
}
void LogicalSetOperation::Accept(OperatorVisitor *v) {
  v->Visit(this);
}
void LogicalJoin::Accept(OperatorVisitor *v) {
  v->Visit(this);
}
void LogicalAggregate::Accept(OperatorVisitor *v) {
  v->Visit(this);
}

}  // namespace optimizer
